/**
 * @file key_driver.c
 * @brief 按键驱动模块实现
 */
#include "key_driver.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "freertos/task.h"

static const char *TAG = "KEY_DRIVER";

/* 按键GPIO定义 */
#define KEY_IO_NUM              0
#define ESP_INTR_FLAG_DEFAULT   0

/* 按键消抖时间定义 */
#define KEY_DEBOUNCE_TIME_MS    20

/* 按键长按时间定义 */
#define KEY_LONG_PRESS_TIME_MS  3000

/* 按键状态定义 */
typedef enum {
    KEY_STATE_IDLE = 0,
    KEY_STATE_PRESS,
    KEY_STATE_RELEASE,
} key_state_t;

/* 静态变量 */
static QueueHandle_t s_key_event_queue = NULL;
static key_event_callback_t s_key_event_callback = NULL;
static volatile key_state_t s_key_state = KEY_STATE_IDLE;
static volatile uint32_t s_key_press_time = 0;
static volatile bool s_key_long_press_sent = false;

/**
 * @brief 按键中断服务函数
 * 
 * @param arg 用户参数
 */
static void IRAM_ATTR key_isr_handler(void *arg)
{
    key_event_t event;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    /* 读取按键状态 */
    if (gpio_get_level(KEY_IO_NUM) == 0) {
        /* 按键按下 */
        event = KEY_EVENT_PRESS;
        s_key_state = KEY_STATE_PRESS;
        s_key_press_time = xTaskGetTickCountFromISR();
        s_key_long_press_sent = false;
    } else {
        /* 按键释放 */
        event = KEY_EVENT_RELEASE;
        s_key_state = KEY_STATE_RELEASE;
    }
    
    /* 发送按键事件到队列 */
    if (s_key_event_queue) {
        xQueueSendFromISR(s_key_event_queue, &event, &xHigherPriorityTaskWoken);
    }
    
    /* 如果有高优先级任务被唤醒，则进行上下文切换 */
    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR();
    }
}

/**
 * @brief 按键驱动任务，用于检测长按事件
 * 
 * @param pvParameters 任务参数
 */
static void key_driver_task(void *pvParameters)
{
    key_event_t event;
    
    while (1) {
        /* 检查是否有长按事件 */
        if (s_key_state == KEY_STATE_PRESS && !s_key_long_press_sent) {
            uint32_t current_time = xTaskGetTickCount();
            if ((current_time - s_key_press_time) * portTICK_PERIOD_MS >= KEY_LONG_PRESS_TIME_MS) {
                event = KEY_EVENT_LONG_PRESS;
                s_key_long_press_sent = true;
                
                /* 发送长按事件到队列 */
                if (s_key_event_queue) {
                    xQueueSend(s_key_event_queue, &event, 0);
                }
                
                /* 调用回调函数 */
                if (s_key_event_callback) {
                    s_key_event_callback(event);
                }
            }
        }
        
        /* 任务延时 */
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

bool key_driver_init(QueueHandle_t event_queue)
{
    ESP_LOGI(TAG, "Initializing key driver");
    
    /* 保存事件队列句柄 */
    s_key_event_queue = event_queue;
    
    /* 配置GPIO */
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << KEY_IO_NUM),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_ANYEDGE,
    };
    
    /* 应用GPIO配置 */
    if (gpio_config(&io_conf) != ESP_OK) {
        ESP_LOGE(TAG, "Failed to configure GPIO");
        return false;
    }
    
    /* 安装GPIO中断服务 */
    if (gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT) != ESP_OK) {
        ESP_LOGE(TAG, "Failed to install GPIO ISR service");
        return false;
    }
    
    /* 添加中断处理函数 */
    if (gpio_isr_handler_add(KEY_IO_NUM, key_isr_handler, NULL) != ESP_OK) {
        ESP_LOGE(TAG, "Failed to add ISR handler");
        return false;
    }
    
    /* 创建按键驱动任务 */
    if (xTaskCreate(key_driver_task, "key_driver_task", 2048, NULL, 10, NULL) != pdPASS) {
        ESP_LOGE(TAG, "Failed to create key driver task");
        return false;
    }
    
    ESP_LOGI(TAG, "Key driver initialized successfully");
    return true;
}

void key_driver_register_callback(key_event_callback_t callback)
{
    s_key_event_callback = callback;
}